package com.jdcjk.util;

import android.content.Context;
import android.text.TextUtils;
import android.util.Log;

import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.Poi;

import java.util.List;

/**
 * Created by dong on 2016/8/10.
 * 百度地图定位工具
 */
public class LocationUtil {
    private final static boolean DEBUG = true;
    private final static String TAG = "LocationUtil";
    private static LocationUtil mInstance;
    private BDLocation mLocation = null;
    private MyLocation mBaseLocation = new MyLocation();
    private static int mode;
    private OnLocationReceiveListener onLocationReceiveListener;

    public static final int GET_LOCATION_ALWAYS = 0;
    public static final int GET_ADDRESS_ONLY = 1;

    public static LocationUtil getInstance(Context context, int mode) {
        if (mInstance == null) {
            synchronized (LocationUtil.class) {
                if (mInstance == null) {
                    mInstance = new LocationUtil(context, mode);
                }
            }
        }
        return mInstance;
    }

    public BDLocationListener myListener = new MyLocationListener();
    private LocationClient mLocationClient;

    public LocationUtil(Context context, int mode) {
        // 声明LocationClient类
        mLocationClient = new LocationClient(context.getApplicationContext());
        // 初始化参数
        LocationUtil.mode = mode;
        initParams();
        // 注册监听函数
        mLocationClient.registerLocationListener(myListener);
    }

    public interface OnLocationReceiveListener {
        // 获取到定位信息时回调
        void onLocationReceive(MyLocation mBaseLocation);

        // 获取到定位地址时回调
        void onAddressReceive(MyLocation mBaseLocation);
    }

    public static class OnLocationReceiveListenerAdapter implements OnLocationReceiveListener {
        @Override
        public void onLocationReceive(MyLocation mBaseLocation) {

        }

        @Override
        public void onAddressReceive(MyLocation mBaseLocation) {

        }
    }

    public void setOnLocationReceiveListener(OnLocationReceiveListener onLocationReceiveListener) {
        this.onLocationReceiveListener = onLocationReceiveListener;
    }

    public void startMonitor() {
        if (DEBUG) Log.d(TAG, "start monitor location");
        if (!mLocationClient.isStarted()) {
            mLocationClient.start();
        }
        if (mLocationClient != null && mLocationClient.isStarted()) {
            mLocationClient.requestLocation();
        } else {
            Log.d("LocSDK3", "locClient is null or not started");
        }
    }

    public void stopMonitor() {
        if (DEBUG) Log.d(TAG, "stop monitor location");
        if (mLocationClient != null && mLocationClient.isStarted()) {
            mLocationClient.stop();
            mInstance = null;
        }
    }

    public BDLocation getLocation() {
        if (DEBUG) Log.d(TAG, "get location");
        return mLocation;
    }

    public MyLocation getBaseLocation() {
        if (DEBUG) Log.d(TAG, "get location");
        return mBaseLocation;
    }

    private void initParams() {
        LocationClientOption option = new LocationClientOption();
        //可选，默认高精度，设置定位模式，高精度，低功耗，仅设备
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        //可选，默认gcj02，设置返回的定位结果坐标系
        option.setCoorType("bd09ll");
        //可选，默认0，即仅定位一次，设置发起定位请求的间隔需要大于等于1000ms才是有效的
        option.setScanSpan(5000);
        //可选，设置是否需要地址信息，默认不需要
        option.setIsNeedAddress(true);
        //可选，默认false,设置是否使用gps
        option.setOpenGps(true);
        //可选，默认false，设置是否当gps有效时按照1S1次频率输出GPS结果
        option.setLocationNotify(true);
        //可选，默认false，设置是否需要位置语义化结果，可以在BDLocation.getLocationDescribe里得到，结果类似于“在北京天安门附近”
        option.setIsNeedLocationDescribe(false);
        //可选，默认false，设置是否需要POI结果，可以在BDLocation.getPoiList里得到
        option.setIsNeedLocationPoiList(false);
        //可选，默认true，定位SDK内部是一个SERVICE，并放到了独立进程，设置是否在stop的时候杀死这个进程，默认不杀死
        option.setIgnoreKillProcess(false);
        //可选，默认false，设置是否收集CRASH信息，默认收集
        option.SetIgnoreCacheException(false);
        //可选，默认false，设置是否需要过滤gps仿真结果，默认需要
        option.setEnableSimulateGps(false);
        mLocationClient.setLocOption(option);
    }

    public class MyLocationListener implements BDLocationListener {
        @Override
        public void onReceiveLocation(BDLocation location) {
            //Receive Location
            if (location == null) {
                return;
            }
            mLocation = location;
            if (!TextUtils.isEmpty(mLocation.getTime())) {
                mBaseLocation.time = mLocation.getTime();
            }
            mBaseLocation.errorCode = mLocation.getLocType();
            // GPS定位结果
            if (location.getLocType() == BDLocation.TypeGpsLocation) {
                mBaseLocation.locType = "GPS定位";
            } else if (location.getLocType() == BDLocation.TypeNetWorkLocation) { // 网络定位结果
                mBaseLocation.locType = "网络定位";
            } else if (location.getLocType() == BDLocation.TypeOffLineLocation) { // 离线定位结果
                mBaseLocation.locType = "离线定位";
            } else if (location.getLocType() == BDLocation.TypeServerError) { // 服务端网络定位失败
                mBaseLocation.locType = "服务端网络定位失败";
            } else if (location.getLocType() == BDLocation.TypeNetWorkException) { // 网络不通畅导致定位失败
                mBaseLocation.locType = "网络不通畅导致定位失败";
            } else if (location.getLocType() == BDLocation.TypeCriteriaException) { // 无法获取有效定位依据导致定位失败，一般是由于手机的原因，处于飞行模式下一般会造成这种结果，可以试着重启手机
                mBaseLocation.locType = "无法获取有效定位依据导致定位失败，一般是由于手机的原因，处于飞行模式下一般会造成这种结果，可以试着重启手机";
            } else {
                mBaseLocation.locType = "定位失败，原因未明";
            }
            mBaseLocation.latitude = BaiDuMapUtil.bd09ll_To_Wgs84(mLocation.getLatitude(), mLocation.getLongitude()).latitude;
            mBaseLocation.longitude = BaiDuMapUtil.bd09ll_To_Wgs84(mLocation.getLatitude(), mLocation.getLongitude()).longitude;
            if (!TextUtils.isEmpty(mLocation.getProvince())) {
                mBaseLocation.province = mLocation.getProvince();
            }
            if (!TextUtils.isEmpty(mLocation.getCity())) {
                mBaseLocation.city = mLocation.getCity();
            }
            if (!TextUtils.isEmpty(mLocation.getDistrict())) {
                mBaseLocation.district = mLocation.getDistrict();
            }
            mBaseLocation.radius = mLocation.getRadius();
            mBaseLocation.speed = mLocation.getSpeed();
            mBaseLocation.satelliteNumber = mLocation.getSatelliteNumber();
            mBaseLocation.altitude = mLocation.getAltitude();
            mBaseLocation.direction = mLocation.getDirection();
            if (!TextUtils.isEmpty(mLocation.getAddrStr())) {
                mBaseLocation.address = mLocation.getAddrStr();
            }
            mBaseLocation.operators = mLocation.getOperators();
            if (!TextUtils.isEmpty(mLocation.getLocationDescribe())) {
                mBaseLocation.locationDescribe = mLocation.getLocationDescribe();
            }
            if (mLocation.getPoiList() != null) {
                mBaseLocation.poiList = mLocation.getPoiList();
            }
            if (DEBUG) Log.d(TAG, mBaseLocation.toString());

            // 获取到有效的定位信息时回调
            if (location.getLocType() == BDLocation.TypeGpsLocation || location.getLocType() == BDLocation.TypeNetWorkLocation) {
                if (LocationUtil.mode == LocationUtil.GET_ADDRESS_ONLY) {
                    if (!TextUtils.isEmpty(mBaseLocation.address)) {
                        onLocationReceiveListener.onAddressReceive(mBaseLocation);
                        stopMonitor();
                        return;
                    }
                    onLocationReceiveListener.onAddressReceive(mBaseLocation);
                } else if (LocationUtil.mode == LocationUtil.GET_LOCATION_ALWAYS) {
                    onLocationReceiveListener.onLocationReceive(mBaseLocation);
                }
            }
        }

        @Override
        public void onConnectHotSpotMessage(String s, int i) {

        }
    }

    public class MyLocation {
        // 时间
        public String time;
        // 错误码类型
        public int errorCode;
        // 定位类型
        public String locType;
        // 经度
        public double latitude;
        // 纬度
        public double longitude;
        // 省份
        public String province;
        // 城市
        public String city;
        // 地区
        public String district;
        // 半径
        public float radius;
        // 速度
        public float speed;
        // 卫星个数
        public int satelliteNumber;
        // 高程
        public double altitude;
        // 方向
        public float direction;
        // 地址
        public String address;
        // 运营商信息
        public int operators;
        // 位置语义化信息
        public String locationDescribe;
        // POI数据
        public List<Poi> poiList;

        public void setLatitude(double latitude) {
            this.latitude = latitude;
        }

        public void setLongitude(double longitude) {
            this.longitude = longitude;
        }

        public String getTime() {
            return time;
        }

        public int getErrorCode() {
            return errorCode;
        }

        public String getLocType() {
            return locType;
        }

        public double getLatitude() {
            return latitude;
        }

        public double getLongitude() {
            return longitude;
        }

        public String getProvince() {
            return province;
        }

        public String getCity() {
            return city;
        }

        public String getDistrict() {
            return district;
        }

        public float getRadius() {
            return radius;
        }

        public float getSpeed() {
            return speed;
        }

        public int getSatelliteNumber() {
            return satelliteNumber;
        }

        public double getAltitude() {
            return altitude;
        }

        public float getDirection() {
            return direction;
        }

        public String getAddress() {
            return address;
        }

        public int getOperators() {
            return operators;
        }

        public String getLocationDescribe() {
            return locationDescribe;
        }

        public List<Poi> getPoiList() {
            return poiList;
        }

        @Override
        public String toString() {
            return "MyLocation{" +
                    "time='" + time + '\'' +
                    ", errorCode=" + errorCode +
                    ", locType='" + locType + '\'' +
                    ", latitude=" + latitude +
                    ", longitude=" + longitude +
                    ", province='" + province + '\'' +
                    ", city='" + city + '\'' +
                    ", district='" + district + '\'' +
                    ", radius=" + radius +
                    ", speed=" + speed +
                    ", satelliteNumber=" + satelliteNumber +
                    ", altitude=" + altitude +
                    ", direction=" + direction +
                    ", address='" + address + '\'' +
                    ", operators=" + operators +
                    ", locationDescribe='" + locationDescribe + '\'' +
                    ", poiList=" + poiList +
                    '}';
        }
    }
}